import categories.CategoriesRegistry;
import categories.CustomerCategory;
import com.svcon.jdbf.DBFWriter;
import org.apache.log4j.Logger;
import readers.RowReader;

import java.text.ParseException;
import java.util.List;

/**
 * Processor that will handle main input to set of output writers conversion flow. Details of conversion
 * ({@link #convertToRow(List<?>)}) should be
 * overidded in concrete clasess.
 */
public abstract class Parser {
    private final static Logger log = Logger.getLogger(Parser.class);

    protected final String name;
    protected final RowReader reader;
    protected final CategoriesRegistry categoriesRegistry;
    protected final OutputWriters writers;

    public Parser(String name, RowReader reader, OutputWriters writers, CategoriesRegistry categoriesRegistry) {
        this.name = name;
        this.reader = reader;
        this.writers = writers;
        this.categoriesRegistry = categoriesRegistry;
    }

    public void parse() throws ParserException, Exception {
        log.info("Started parsing with " + this);

        reader.printHeader(log);

        long now = System.currentTimeMillis();

        int i=0;
        CallRow row = null;
        List<?> values = null;

        try {
            while((values = reader.read()) != null) {
                if(log.isTraceEnabled()) {
                    log.trace("read values: " + values);
                }

                row = convertToRow(values);

                // work with more than 5sec duration
                if(row.getDurationSec() > 5) {
                    if(log.isTraceEnabled()) {
                        log.trace("writing " + i + " row: " + row);
                    }

                    CustomerCategory c = categoriesRegistry.getByNumber(row.getCustomerId());
                    DBFWriter writer = writers.getFor(c);

                    postCorrectValues(c, row);

                    writer.addRecord(
                            new Object[] {
                                "XYZ",
                                "XYZ",
                                Long.toString(row.getCustomerId()), // xxxcode
                                row.getDateTime(), //date
                                row.getTime(), //time
                                "XYZ", // desc1
                                row.getDestNumber(),  // B-number
                                row.getDurationMin(), // duration
                                row.getDurationMin(), //duration
                                0,
                                0,
                                0,
                                0,
                                0,
                                0
                            }
                        );
                }
                i++;
            }
        } catch (Throwable e) {
            throw new ParserException(i, row, values, e);
        } finally {
            log.info("Total " + i + " rows processed");
            log.info(" in " + ((System.currentTimeMillis() - now) / 100) + "s");

            reader.close();
        }
    }

    protected abstract CallRow convertToRow(List<?> values) throws ParseException;

    protected void postCorrectValues(final CustomerCategory customerCategory, CallRow row) {
        long customerId = row.getCustomerId();
        if(customerId == 501) {
            // billing application don't handle XXX number's correctly
            // by requrements will replace it on XXX0
            row.setCustomerId(customerId * 10000);
        } else if(customerId >= 100  && customerId <= 999) {
            // billing application don't handle XXX number's correctly
            // by requrements will replace it on XXX0
            row.setCustomerId(customerId * 10);
        }
    }

    public String toString() {
        return name;
    }
}
